(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([typeof document === "object" ? document.currentScript : undefined, {
"[turbopack]/browser/dev/hmr-client/hmr-client.ts [app-client] (ecmascript)": ((__turbopack_context__) => {
"use strict";
var { g: global, __dirname } = __turbopack_context__;
{
///
///
///
///
__turbopack_context__.s({
"connect": (()=>connect),
"setHooks": (()=>setHooks),
"subscribeToUpdate": (()=>subscribeToUpdate)
});
function connect({ addMessageListener, sendMessage, onUpdateError = console.error }) {
addMessageListener((msg)=>{
switch(msg.type){
case "turbopack-connected":
handleSocketConnected(sendMessage);
break;
default:
try {
if (Array.isArray(msg.data)) {
for(let i = 0; i < msg.data.length; i++){
handleSocketMessage(msg.data[i]);
}
} else {
handleSocketMessage(msg.data);
}
applyAggregatedUpdates();
} catch (e) {
console.warn("[Fast Refresh] performing full reload\n\n" + "Fast Refresh will perform a full reload when you edit a file that's imported by modules outside of the React rendering tree.\n" + "You might have a file which exports a React component but also exports a value that is imported by a non-React component file.\n" + "Consider migrating the non-React component export to a separate file and importing it into both files.\n\n" + "It is also possible the parent component of the component you edited is a class component, which disables Fast Refresh.\n" + "Fast Refresh requires at least one parent function component in your React tree.");
onUpdateError(e);
location.reload();
}
break;
}
});
const queued = globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS;
if (queued != null && !Array.isArray(queued)) {
throw new Error("A separate HMR handler was already registered");
}
globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS = {
push: ([chunkPath, callback])=>{
subscribeToChunkUpdate(chunkPath, sendMessage, callback);
}
};
if (Array.isArray(queued)) {
for (const [chunkPath, callback] of queued){
subscribeToChunkUpdate(chunkPath, sendMessage, callback);
}
}
}
const updateCallbackSets = new Map();
function sendJSON(sendMessage, message) {
sendMessage(JSON.stringify(message));
}
function resourceKey(resource) {
return JSON.stringify({
path: resource.path,
headers: resource.headers || null
});
}
function subscribeToUpdates(sendMessage, resource) {
sendJSON(sendMessage, {
type: "turbopack-subscribe",
...resource
});
return ()=>{
sendJSON(sendMessage, {
type: "turbopack-unsubscribe",
...resource
});
};
}
function handleSocketConnected(sendMessage) {
for (const key of updateCallbackSets.keys()){
subscribeToUpdates(sendMessage, JSON.parse(key));
}
}
// we aggregate all pending updates until the issues are resolved
const chunkListsWithPendingUpdates = new Map();
function aggregateUpdates(msg) {
const key = resourceKey(msg.resource);
let aggregated = chunkListsWithPendingUpdates.get(key);
if (aggregated) {
aggregated.instruction = mergeChunkListUpdates(aggregated.instruction, msg.instruction);
} else {
chunkListsWithPendingUpdates.set(key, msg);
}
}
function applyAggregatedUpdates() {
if (chunkListsWithPendingUpdates.size === 0) return;
hooks.beforeRefresh();
for (const msg of chunkListsWithPendingUpdates.values()){
triggerUpdate(msg);
}
chunkListsWithPendingUpdates.clear();
finalizeUpdate();
}
function mergeChunkListUpdates(updateA, updateB) {
let chunks;
if (updateA.chunks != null) {
if (updateB.chunks == null) {
chunks = updateA.chunks;
} else {
chunks = mergeChunkListChunks(updateA.chunks, updateB.chunks);
}
} else if (updateB.chunks != null) {
chunks = updateB.chunks;
}
let merged;
if (updateA.merged != null) {
if (updateB.merged == null) {
merged = updateA.merged;
} else {
// Since `merged` is an array of updates, we need to merge them all into
// one, consistent update.
// Since there can only be `EcmascriptMergeUpdates` in the array, there is
// no need to key on the `type` field.
let update = updateA.merged[0];
for(let i = 1; i < updateA.merged.length; i++){
update = mergeChunkListEcmascriptMergedUpdates(update, updateA.merged[i]);
}
for(let i = 0; i < updateB.merged.length; i++){
update = mergeChunkListEcmascriptMergedUpdates(update, updateB.merged[i]);
}
merged = [
update
];
}
} else if (updateB.merged != null) {
merged = updateB.merged;
}
return {
type: "ChunkListUpdate",
chunks,
merged
};
}
function mergeChunkListChunks(chunksA, chunksB) {
const chunks = {};
for (const [chunkPath, chunkUpdateA] of Object.entries(chunksA)){
const chunkUpdateB = chunksB[chunkPath];
if (chunkUpdateB != null) {
const mergedUpdate = mergeChunkUpdates(chunkUpdateA, chunkUpdateB);
if (mergedUpdate != null) {
chunks[chunkPath] = mergedUpdate;
}
} else {
chunks[chunkPath] = chunkUpdateA;
}
}
for (const [chunkPath, chunkUpdateB] of Object.entries(chunksB)){
if (chunks[chunkPath] == null) {
chunks[chunkPath] = chunkUpdateB;
}
}
return chunks;
}
function mergeChunkUpdates(updateA, updateB) {
if (updateA.type === "added" && updateB.type === "deleted" || updateA.type === "deleted" && updateB.type === "added") {
return undefined;
}
if (updateA.type === "partial") {
invariant(updateA.instruction, "Partial updates are unsupported");
}
if (updateB.type === "partial") {
invariant(updateB.instruction, "Partial updates are unsupported");
}
return undefined;
}
function mergeChunkListEcmascriptMergedUpdates(mergedA, mergedB) {
const entries = mergeEcmascriptChunkEntries(mergedA.entries, mergedB.entries);
const chunks = mergeEcmascriptChunksUpdates(mergedA.chunks, mergedB.chunks);
return {
type: "EcmascriptMergedUpdate",
entries,
chunks
};
}
function mergeEcmascriptChunkEntries(entriesA, entriesB) {
return {
...entriesA,
...entriesB
};
}
function mergeEcmascriptChunksUpdates(chunksA, chunksB) {
if (chunksA == null) {
return chunksB;
}
if (chunksB == null) {
return chunksA;
}
const chunks = {};
for (const [chunkPath, chunkUpdateA] of Object.entries(chunksA)){
const chunkUpdateB = chunksB[chunkPath];
if (chunkUpdateB != null) {
const mergedUpdate = mergeEcmascriptChunkUpdates(chunkUpdateA, chunkUpdateB);
if (mergedUpdate != null) {
chunks[chunkPath] = mergedUpdate;
}
} else {
chunks[chunkPath] = chunkUpdateA;
}
}
for (const [chunkPath, chunkUpdateB] of Object.entries(chunksB)){
if (chunks[chunkPath] == null) {
chunks[chunkPath] = chunkUpdateB;
}
}
if (Object.keys(chunks).length === 0) {
return undefined;
}
return chunks;
}
function mergeEcmascriptChunkUpdates(updateA, updateB) {
if (updateA.type === "added" && updateB.type === "deleted") {
// These two completely cancel each other out.
return undefined;
}
if (updateA.type === "deleted" && updateB.type === "added") {
const added = [];
const deleted = [];
const deletedModules = new Set(updateA.modules ?? []);
const addedModules = new Set(updateB.modules ?? []);
for (const moduleId of addedModules){
if (!deletedModules.has(moduleId)) {
added.push(moduleId);
}
}
for (const moduleId of deletedModules){
if (!addedModules.has(moduleId)) {
deleted.push(moduleId);
}
}
if (added.length === 0 && deleted.length === 0) {
return undefined;
}
return {
type: "partial",
added,
deleted
};
}
if (updateA.type === "partial" && updateB.type === "partial") {
const added = new Set([
...updateA.added ?? [],
...updateB.added ?? []
]);
const deleted = new Set([
...updateA.deleted ?? [],
...updateB.deleted ?? []
]);
if (updateB.added != null) {
for (const moduleId of updateB.added){
deleted.delete(moduleId);
}
}
if (updateB.deleted != null) {
for (const moduleId of updateB.deleted){
added.delete(moduleId);
}
}
return {
type: "partial",
added: [
...added
],
deleted: [
...deleted
]
};
}
if (updateA.type === "added" && updateB.type === "partial") {
const modules = new Set([
...updateA.modules ?? [],
...updateB.added ?? []
]);
for (const moduleId of updateB.deleted ?? []){
modules.delete(moduleId);
}
return {
type: "added",
modules: [
...modules
]
};
}
if (updateA.type === "partial" && updateB.type === "deleted") {
// We could eagerly return `updateB` here, but this would potentially be
// incorrect if `updateA` has added modules.
const modules = new Set(updateB.modules ?? []);
if (updateA.added != null) {
for (const moduleId of updateA.added){
modules.delete(moduleId);
}
}
return {
type: "deleted",
modules: [
...modules
]
};
}
// Any other update combination is invalid.
return undefined;
}
function invariant(_, message) {
throw new Error(`Invariant: ${message}`);
}
const CRITICAL = [
"bug",
"error",
"fatal"
];
function compareByList(list, a, b) {
const aI = list.indexOf(a) + 1 || list.length;
const bI = list.indexOf(b) + 1 || list.length;
return aI - bI;
}
const chunksWithIssues = new Map();
function emitIssues() {
const issues = [];
const deduplicationSet = new Set();
for (const [_, chunkIssues] of chunksWithIssues){
for (const chunkIssue of chunkIssues){
if (deduplicationSet.has(chunkIssue.formatted)) continue;
issues.push(chunkIssue);
deduplicationSet.add(chunkIssue.formatted);
}
}
sortIssues(issues);
hooks.issues(issues);
}
function handleIssues(msg) {
const key = resourceKey(msg.resource);
let hasCriticalIssues = false;
for (const issue of msg.issues){
if (CRITICAL.includes(issue.severity)) {
hasCriticalIssues = true;
}
}
if (msg.issues.length > 0) {
chunksWithIssues.set(key, msg.issues);
} else if (chunksWithIssues.has(key)) {
chunksWithIssues.delete(key);
}
emitIssues();
return hasCriticalIssues;
}
const SEVERITY_ORDER = [
"bug",
"fatal",
"error",
"warning",
"info",
"log"
];
const CATEGORY_ORDER = [
"parse",
"resolve",
"code generation",
"rendering",
"typescript",
"other"
];
function sortIssues(issues) {
issues.sort((a, b)=>{
const first = compareByList(SEVERITY_ORDER, a.severity, b.severity);
if (first !== 0) return first;
return compareByList(CATEGORY_ORDER, a.category, b.category);
});
}
const hooks = {
beforeRefresh: ()=>{},
refresh: ()=>{},
buildOk: ()=>{},
issues: (_issues)=>{}
};
function setHooks(newHooks) {
Object.assign(hooks, newHooks);
}
function handleSocketMessage(msg) {
sortIssues(msg.issues);
handleIssues(msg);
switch(msg.type){
case "issues":
break;
case "partial":
// aggregate updates
aggregateUpdates(msg);
break;
default:
// run single update
const runHooks = chunkListsWithPendingUpdates.size === 0;
if (runHooks) hooks.beforeRefresh();
triggerUpdate(msg);
if (runHooks) finalizeUpdate();
break;
}
}
function finalizeUpdate() {
hooks.refresh();
hooks.buildOk();
// This is used by the Next.js integration test suite to notify it when HMR
// updates have been completed.
// TODO: Only run this in test environments (gate by `process.env.__NEXT_TEST_MODE`)
if (globalThis.__NEXT_HMR_CB) {
globalThis.__NEXT_HMR_CB();
globalThis.__NEXT_HMR_CB = null;
}
}
function subscribeToChunkUpdate(chunkListPath, sendMessage, callback) {
return subscribeToUpdate({
path: chunkListPath
}, sendMessage, callback);
}
function subscribeToUpdate(resource, sendMessage, callback) {
const key = resourceKey(resource);
let callbackSet;
const existingCallbackSet = updateCallbackSets.get(key);
if (!existingCallbackSet) {
callbackSet = {
callbacks: new Set([
callback
]),
unsubscribe: subscribeToUpdates(sendMessage, resource)
};
updateCallbackSets.set(key, callbackSet);
} else {
existingCallbackSet.callbacks.add(callback);
callbackSet = existingCallbackSet;
}
return ()=>{
callbackSet.callbacks.delete(callback);
if (callbackSet.callbacks.size === 0) {
callbackSet.unsubscribe();
updateCallbackSets.delete(key);
}
};
}
function triggerUpdate(msg) {
const key = resourceKey(msg.resource);
const callbackSet = updateCallbackSets.get(key);
if (!callbackSet) {
return;
}
for (const callback of callbackSet.callbacks){
callback(msg);
}
if (msg.type === "notFound") {
// This indicates that the resource which we subscribed to either does not exist or
// has been deleted. In either case, we should clear all update callbacks, so if a
// new subscription is created for the same resource, it will send a new "subscribe"
// message to the server.
// No need to send an "unsubscribe" message to the server, it will have already
// dropped the update stream before sending the "notFound" message.
updateCallbackSets.delete(key);
}
}
}}),
}]);
//# sourceMappingURL=%5Bturbopack%5D_browser_dev_hmr-client_hmr-client_ts_61dcf9ba._.js.map